﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace WcfContrib.Extensions.OutputControllers
{
    abstract class OutputControllerBase : IOutputController
    {
        Dictionary<OutputArgument, object> instanceState;

        [ThreadStatic]
        Dictionary<OutputArgument, object> state;

        protected bool TryGetArgument<T>(OutputArgument argument, out T? value)
            where T : struct
        {
            T valueMatch;
            if (TryGetArgument(argument, out valueMatch))
            {
                value = valueMatch;

                return true;
            }

            value = null;
            return false;
        }

        protected bool TryGetArgument<T>(OutputArgument argument, out T value)
        {
            return TryGetArgument<T>(state, argument, out value)
                || TryGetArgument<T>(instanceState, argument, out value);
        }

        static bool TryGetArgument<T>(Dictionary<OutputArgument, object> state, OutputArgument argument, out T value)
        {
            object valueMatch;
            if (state != null && state.TryGetValue(argument, out valueMatch))
            {
                if (valueMatch != null && valueMatch is T)
                {
                    value = (T)valueMatch;

                    return true;
                }
            }

            value = default(T);
            return false;
        }

        #region IOutputController Members
        public void LoadState(Dictionary<OutputArgument, object> state)
        {
            this.instanceState = state;

            OnLoadState();
        }

        public void OutputMessage(string message, Dictionary<OutputArgument, object> state)
        {
            this.state = state;

            OnOutputMessage(message);

            this.state = null;
        }
        #endregion

        protected abstract void OnLoadState();
        protected abstract void OnOutputMessage(string message);
    }
}
